import {
  Controller,
  UseGuards,
  UploadedFiles,
  BadRequestException,
} from '@nestjs/common';
import {
  Crud,
  CrudController,
  Override,
  CrudRequest,
  ParsedRequest,
  ParsedBody,
} from '@nestjsx/crud';
import { ApiTags, ApiBearerAuth, ApiConsumes } from '@nestjs/swagger';
import { FileUtils } from '@/utils';
import { deserialize, deserializeArray } from 'class-transformer';
import { RequestDtoRelationTransformer } from '@/interfaces';
import { AuthGuard } from '@/guards';
import { Post as PostEntity, ResourceFile, Song } from '../entities';
import { PostsService } from '../services';
import { User } from '@/modules/users';

@Crud({
  model: {
    type: PostEntity,
  },
  query: {
    limit: 25,
    maxLimit: 100,
    join: {
      video: {
        allow: ['mimetype', 'size', 'path'],
      },
      poster: {},
      relatedSongs: {},
    },
  },
  routes: {
    exclude: ['createManyBase'],
    createOneBase: {
      interceptors: [
        FileUtils.multipleFileFieldsUploader(
          [
            { name: 'video', maxCount: 1 },
            { name: 'coverImage', maxCount: 1 },
          ],
          ['video', 'image'],
        ),
      ],
    },
    updateOneBase: {
      interceptors: [
        FileUtils.multipleFileFieldsUploader(
          [
            { name: 'video', maxCount: 1 },
            { name: 'coverImage', maxCount: 1 },
          ],
          ['video', 'image'],
        ),
      ],
    },
    replaceOneBase: {
      interceptors: [
        FileUtils.multipleFileFieldsUploader(
          [
            { name: 'video', maxCount: 1 },
            { name: 'coverImage', maxCount: 1 },
          ],
          ['video', 'image'],
        ),
      ],
    },
    deleteOneBase: {
      decorators: [UseGuards(AuthGuard), ApiBearerAuth()],
    },
  },
})
@ApiTags('posts')
@Controller('resources/posts')
// eslint-disable-next-line prettier/prettier
export class PostsController implements CrudController<PostEntity>, RequestDtoRelationTransformer<PostEntity> {
  constructor(public service: PostsService) {}

  get base(): CrudController<PostEntity> {
    return this;
  }

  dtoRelationTransform(dto: PostEntity) {
    try {
      if (typeof dto.tags === 'string') {
        dto.tags = JSON.parse(dto.tags);
      }
      if (typeof dto.video === 'string') {
        dto.video = deserialize(ResourceFile, dto.video);
      }
      if (typeof dto.poster === 'string') {
        dto.poster = deserialize(User, dto.poster);
      }
      if (typeof dto.relatedSongs === 'string') {
        dto.relatedSongs = deserializeArray(Song, dto.relatedSongs);
      }
    } catch (e) {
      if (e instanceof SyntaxError) {
        throw new BadRequestException(e.message, e.name);
      }
      throw new BadRequestException();
    }
    return dto;
  }

  private uploadedFilesHandler(
    dto: PostEntity,
    files: Express.Multer.File[][],
  ): PostEntity {
    if (files['coverImage']) {
      dto.coverImage = files['coverImage'][0].path;
    }
    if (files['video']) {
      dto.video = new ResourceFile(files['video'][0]);
    }
    return dto;
  }

  @UseGuards(AuthGuard)
  @ApiBearerAuth()
  @ApiConsumes('multipart/form-data')
  @Override()
  createOne(
    @ParsedRequest() req: CrudRequest,
    @ParsedBody() dto: PostEntity,
    @UploadedFiles() files: Express.Multer.File[][],
  ) {
    dto = this.dtoRelationTransform(dto);
    dto = this.uploadedFilesHandler(dto, files);
    return this.base.createOneBase(req, dto);
  }

  @UseGuards(AuthGuard)
  @ApiBearerAuth()
  @ApiConsumes('multipart/form-data')
  @Override()
  updateOne(
    @ParsedRequest() req: CrudRequest,
    @ParsedBody() dto: PostEntity,
    @UploadedFiles() files: Express.Multer.File[][],
  ) {
    dto = this.dtoRelationTransform(dto);
    dto = this.uploadedFilesHandler(dto, files);
    return this.base.updateOneBase(req, dto);
  }

  @UseGuards(AuthGuard)
  @ApiBearerAuth()
  @ApiConsumes('multipart/form-data')
  @Override()
  replaceOne(
    @ParsedRequest() req: CrudRequest,
    @ParsedBody() dto: PostEntity,
    @UploadedFiles() files: Express.Multer.File[][],
  ) {
    dto = this.dtoRelationTransform(dto);
    dto = this.uploadedFilesHandler(dto, files);
    return this.base.replaceOneBase(req, dto);
  }
}
